using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;

namespace ca.metaobjects.csogateway.Configuration
{
	/// <summary>
	/// Configuration section for all configuration settings of the CSO Gateway
	/// </summary>
	public sealed class CsoGatewayConfigSection : ConfigurationSection
	{
		/// <summary>
		/// Gets a configuration element containing all the configuration settings related to creating client-side values from server-side objects
		/// </summary>
		[ConfigurationProperty("ToClientSideConfig", IsRequired=true)]
		public ToClientSideConfigElement ToClientSideConfig
		{
			get
			{
				return this["ToClientSideConfig"] as ToClientSideConfigElement;
			}
		}

		/// <summary>
		/// Gets a configuration element containing all the configuration settings related to creating server-side objects from client-side values
		/// </summary>
		[ConfigurationProperty("ToServerSideConfig", IsRequired=true)]
		public ToServerSideConfigElement ToServerSideConfig
		{
			get
			{
				return this["ToServerSideConfig"] as ToServerSideConfigElement;
			}
		}
	}

	/// <summary>
	/// Represents the configuration settings for the transformation of server-side object into client-side values.
	/// </summary>
    public class ToClientSideConfigElement : ConfigurationElement
    {
		/// <summary>
		/// <para>
		/// Gets or sets the name of the namespace that cso-generated types will be placed in if the value of
		/// the <see href="CsoGeneratedTypeAttribute.ClientSideNamespace" /> property
		/// is not specified and if the namespace name for this type is not
		/// declared in the <see cref="ClientSideNamespaceOfTypes" /> element.
		/// </para>
		/// <para>
		/// This configuration setting is not required and if it is not set, it defaults to "UserDefinedTypes"
		/// </para>
		/// </summary>
		[ConfigurationProperty("DefaultNamespace", DefaultValue = "UserDefinedTypes", IsRequired=false)]
		public string DefaultNamespace
		{
			get
			{
				return this["DefaultNamespace"] as string;
			}
			set
			{
				this["DefaultNamespace"] = value;
			}
		}

		/// <summary>
		/// <para>
		/// Gets or sets a boolean value indicating whether the Type Morpher should take into account the properties declared in ancestor classes when
		/// creating a cso-generated class for a cso-ready class. The value of the <see href="CsoGeneratedTypeAttribute.IgnoreBaseClass" />> property
		/// has priority over this configuration setting.
		/// </para>
		/// <para>
		/// This configuration setting is not required and if it is not set, defaults to false.
		/// </para>
		/// </summary>		
		[ConfigurationProperty("IgnoreBaseClass", DefaultValue = "false", IsRequired=false)]
		public bool IgnoreBaseClass
		{
			get
			{
				return (bool) this["IgnoreBaseClass"];
			}
			set
			{
				this["IgnoreBaseClass"] = value;
			}
		}

		/// <summary>
		/// <para>
		/// Gets or sets a boolean value indicating whether to throw an exception when the Object Gateway encouters a <see cref="System.Int64" /> value
		/// that is too small or too large to be exactly represented by a javascript value of type Number.
		/// </para>
		/// <para>
		/// This configuration setting is not required and if it is not set, defaults to true.
		/// </para>
		/// </summary>
		[ConfigurationProperty("ExceptionOnPrecisionLossInt64", DefaultValue=true, IsRequired=false)]
		public bool ExceptionOnPrecisionLossInt64
		{
			get
			{
				return (bool)this["ExceptionOnPrecisionLossInt64"];
			}
			set
			{
				this["ExceptionOnPrecisionLossInt64"] = value;
			}
		}

		/// <summary>
		/// <para>
		/// Gets or sets a boolean value indicating whether to throw an exception when the Object Gateway encouters a <see cref="System.UInt64" /> value
		/// that is too large to be represented exactly by a javascript value of type Number.
		/// </para>
		/// <para>
		/// This configuration setting is not required and if it is not set, defaults to true.
		/// </para>
		/// </summary>
		[ConfigurationProperty("ExceptionOnPrecisionLossUInt64", DefaultValue = true, IsRequired=false)]
		public bool ExceptionOnPrecisionLossUInt64
		{
			get
			{
				return (bool)this["ExceptionOnPrecisionLossUInt64"];
			}
			set
			{
				this["ExceptionOnPrecisionLossUInt64"] = value;
			}
		}

		/// <summary>
		/// <para>
		/// Gets or sets a boolean value indicating whether to throw an exception when the Object Gateway encouters a <see cref="System.Decimal" /> value
		/// that has too many effective precision bits to be represented exactly by a javascript value of type Number.
		/// </para>
		/// <para>
		/// This configuration setting is not required and if it is not set, defaults to true.
		/// </para>
		/// </summary>
		[ConfigurationProperty("ExceptionOnPrecisionLossDecimal", DefaultValue = true, IsRequired=false)]
		public bool ExceptionOnPrecisionLossDecimal
		{
			get
			{
				return (bool)this["ExceptionOnPrecisionLossDecimal"];
			}
			set
			{
				this["ExceptionOnPrecisionLossDecimal"] = value;
			}
		}

		/// <summary>
		/// <para>
		/// Gets a configuration element collection containing the client side namespace names for some cso-ready types.
		/// </para>
		/// <para>
		/// If a non-null value is passed to the clientSideNamespace parameter of the CsoGeneratedTypeAttribute attribute
		/// (see <see href="ca.metaobjects.csogateway.CsoGeneratedTypeAttribute.ClientSideNamespace" />)
		/// it overrides what is specified here.
		/// </para>
		/// <para>
		/// This configuration setting element is not required and can be omitted.
		/// </para>
		/// </summary>
		[ConfigurationProperty("ClientSideNamespaceOfTypes")]
		public TypeStringElementCollection ClientSideNamespaceOfTypes
        {
            get
            {
				return this["ClientSideNamespaceOfTypes"] as TypeStringElementCollection;
            }
        }

		/// <summary>
		/// <para>
		/// Gets a configuration element collection containing the extension URLs of the extension javascript files for some cso-ready types.
		/// </para>
		/// <para>
		/// If a non-null value is passed to the extensionUrl parameter of the CsoGeneratedTypeAttribute attribute
		/// (see <see href="ca.metaobjects.csogateway.CsoGeneratedTypeAttribute.ExtensionUrl" />)
		/// it overrides what is specified here.
		/// </para>
		/// <para>
		/// This configuration setting element is not required and can be omitted.
		/// </para>
		/// </summary>
		[ConfigurationProperty("ExtensionUrls")]
		public TypeStringElementCollection ExtensionUrls
		{
			get
			{
				return this["ExtensionUrls"] as TypeStringElementCollection;
			}
		}
    }

	/// <summary>
	/// Represents the configuration settings for the transformation of client-side values into server-side objects.
	/// </summary>
	public class ToServerSideConfigElement : ConfigurationElement
	{
	}

	/// <summary>
	/// Represents a collection of configuration elements composed of 2 strings. The first being the full name or the assembly-qualified name of a System.Type, the second being
	/// some value associated with that System.Type value.
	/// </summary>
	public class TypeStringElementCollection : ConfigurationElementCollection
    {
		/// <summary>
		/// Gets or sets the <see cref="TypeStringElement"/> object at the specified index in the collection.
		/// </summary>
		/// <param name="index">The zero-based index in the collection</param>
		/// <returns>The <see cref="TypeStringElement" /> object at the index specified by <paramref name="index" /></returns>
		public TypeStringElement this[int index]
        {
            get
            {
				return base.BaseGet(index) as TypeStringElement;
            }
            set
            {
                if (base.BaseGet(index) != null)
                {
                    base.BaseRemoveAt(index);
                }
                this.BaseAdd(index, value);
            }
        }

		/// <summary>
		/// Determines whether this collection contains a configuration element for the given <see cref="System.Type" />.
		/// </summary>
		/// <param name="aType">The <see cref="System.Type" /> to look for.</param>
		/// <returns>true if this collection contains a <see cref="TypeStringElement" /> object with a <see cref="TypeStringElement.TypeFullName"/> value equals to the
		/// full name or the assembly-qualified name of the given <see cref="System.Type" />, returns false otherwise. </returns>
		public bool ContainsElementForType(Type aType)
		{
			bool found = false;
			for (int i = 0; i < this.Count; i++)
			{
				if ((this[i].TypeFullName == aType.FullName) || (this[i].TypeFullName == aType.AssemblyQualifiedName))
				{
					found = true;
					break;
				}
			}
			return found;
		}

		/// <summary>
		/// Obtains the value associated with the given <see cref="System.Type" />.
		/// </summary>
		/// <param name="aType">The <see cref="System.Type" /> to return the value for.</param>
		/// <returns>The string value of <see cref="TypeStringElement.Value"/> if the given <see cref="System.Type" /> is found. Returns null otherwise</returns>
		public string ValueForType(Type aType)
		{
			string theValue = null;
			for (int i = 0; i < this.Count; i++)
			{
				if (this[i].TypeFullName == aType.FullName)
				{
					theValue = this[i].Value;
					break;
				}
			}

			return theValue;
		}

		
		/// <summary>
		/// Creates a new configuration element for this collection.
		/// </summary>
		/// <returns>A new TypeStringElement object.</returns>
        protected override ConfigurationElement CreateNewElement()
        {
            return new TypeStringElement();
        }

		/// <summary>
		/// Obtains a key for a configuration element of type <see cref="TypeStringElement"/>
		/// </summary>
		/// <param name="element">The configuration element to get the key for.</param>
		/// <returns>The value of the TypeFullName property of the TypeStringElement object passed to this method.</returns>
        protected override object GetElementKey(ConfigurationElement element)
        {
			return ((TypeStringElement)element).TypeFullName;
        }
    }

	/// <summary>
	/// Represents a configuration element composed of 2 strings. The first being the full name or the assembly-qualified name of a System.Type, the second being
	/// some value associated with that System.Type value.
	/// </summary>
	public class TypeStringElement : ConfigurationElement
	{
		/// <summary>
		/// Gets or sets either the full name or the assembly-qualified name of some existing type. No exception is thrown if a value that does not correspond to
		/// a loaded type is set.
		/// </summary>
		[ConfigurationProperty("TypeFullName")]
		public string TypeFullName
		{
			get
			{
				return this["TypeFullName"] as string;
			}
			set
			{
				this["TypeFullName"] = value;
			}
		}

		/// <summary>
		/// Gets or sets the arbitrary value associated with this TypeStringElement object.
		/// </summary>
		[ConfigurationProperty("Value")]
		public string Value
		{
			get
			{
				return this["Value"] as string;
			}
			set
			{
				this["Value"] = value;
			}
		}

		/// <summary>
		/// Creates an empty TypeStringElement.
		/// </summary>
		public TypeStringElement()
		{
		}
	}
}
